package wn.lizzy.essay.service;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.annotation.Resource;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.xiaoleilu.hutool.crypto.SecureUtil;

import wn.lizzy.essay.entity.Classification;
import wn.lizzy.essay.entity.User;
import wn.lizzy.essay.repository.ClassificationRepository;
import wn.lizzy.essay.repository.UserRepository;
import wn.lizzy.essay.util.ToolKits;

@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class UserService {
	// 日志
	private static final Logger logger = LogManager.getLogger(UserService.class);
	@Resource
	private UserRepository userRepository;
	@Resource
	private ClassificationRepository classificationRepository;
	/**
	 * 通过用户名，密码获取登录信息
	 * @param username
	 * @param password
	 * @return
	 * @throws EntityNotFoundException
	 * @throws BadCredentialsException
	 * @throws LockedException
	 * @throws Exception
	 */
	public User checkedUser(String username, String password) throws EntityNotFoundException, BadCredentialsException, LockedException, Exception {
		Long id = this.getUidByUsername(username);
		Optional<User> op = this.getEntityInfo(id);
		this.checkPassword(op.get(), password);
		this.checkLocked(op.get());
		return op.get();
	}
	
	/**
	 * 分页获取用户列表
	 * @param queryPrams
	 * @param pageable
	 * @return
	 */
	@Transactional(propagation = Propagation.SUPPORTS, readOnly = false, rollbackFor = { Exception.class })
	public Page<User> getUserList(Map<String,Object> queryPrams, Pageable pageable){
		return userRepository.findAll((root, query, cb) -> {
			Predicate predicate = cb.conjunction();
			List<Expression<Boolean>> expressions = predicate.getExpressions();
			
			// *****************  此处添加约束条件   start ***************************
			String username = (String)queryPrams.get("username");
			String name = (String)queryPrams.get("name");
			if(!Strings.isNullOrEmpty(username)) {
				expressions.add(cb.like(root.<String> get("username"), "%"+username+"%"));
			}
			if(!Strings.isNullOrEmpty(name)) {
				expressions.add(cb.like(root.<String> get("name"), "%"+name+"%"));
			}
			// *****************  此处添加约束条件   end ***************************
			Order[] order = new Order[1];
			order[0] = cb.asc(root.get("userId"));
			query.orderBy(order);
			return predicate;
		} , pageable);
	}
	
	/**
	 * 通过唯一键值获取用户信息
	 * @param uid
	 * @return
	 * @throws EntityNotFoundException
	 * @throws Exception
	 */
	public User findUserByUid(Long uid) throws EntityNotFoundException, Exception {
		return getEntityInfo(uid).get();
	}
	
	/**
	 * 保存用户信息
	 * @param user
	 * @param password
	 * @param unitid
	 */
	@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = { Exception.class })
	public void saveUser(User user,String password) {
		user.setPassword( this.generatePassword(user.getUsername(), password) );
		user.setName(user.getName());
		user.setDescription(user.getDescription());
		user.setValid(true);
		userRepository.save(user);
	}
	
	/**
	 * 更新用户信息
	 * @param userid
	 * @param user
	 * @param unitid
	 */
	@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = { Exception.class })
	public void updateUser(User user, Long uid) {
		User userUpdate=userRepository.findOne(uid);
		userUpdate.setName(user.getName());
		userUpdate.setDescription(user.getDescription());
		userUpdate.setValid(user.getValid());
		userRepository.save(userUpdate);
	}
	
	/**
	 * 更新用户管理的栏目
	 * @param userid
	 * @param rolestr
	 */
	@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = { Exception.class })
	public void updateUserClass(Long userid,String classificationStr) {
		User user=userRepository.findOne(userid);
		if(!Strings.isNullOrEmpty(classificationStr)){
			List<Classification> classificationList= Lists.newArrayList();
			List<String> classlist=ToolKits.StringsOper(classificationStr,",");
			for(int i=0;i<classlist.size();i++){
				classificationList.add(classificationRepository.findOne(Long.parseLong(classlist.get(i))));
			}
			user.setClassificationList(classificationList);
		}
		userRepository.save(user);
	}
	
	/**
	 * 删除用户
	 * @param id
	 * @throws Exception
	 */
	@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = { Exception.class })
	public void deleteUser(Long id) throws Exception {
		userRepository.delete(id);
	}
	/**
	 * 判断用户是否存在
	 * @param code
	 * @return
	 */
	public boolean ifUserExist(String username){
		boolean ifexist=false;
		if(userRepository.findByUsername(username)!=null)
			ifexist=true;
		return ifexist;
	}
	
	/**
	 * 获取已存在的 用户
	 * 不存在则抛出 EntityNotFoundException
	 * @param id 用户id
	 * @return
	 * @throws EntityNotFoundException
	 * @throws Exception
	 */
	private Optional<User> getEntityInfo(Long id) throws EntityNotFoundException, Exception {
		this.checkId(id);
		Optional<User> op = Optional.ofNullable(userRepository.findOne(id));
		userIsNotExist(op, String.valueOf(id));
		return op;
	}

	/**
	 * 通过Username获取id
	 * @param uid
	 * @return
	 */
	private Long getUidByUsername(String username) {
		Optional<User> op = Optional.ofNullable(userRepository.findByUsername(username));
		this.userIsNotExist(op, username);
		return op.get().getUid();
	}
	
	/**
	 * 用户不存在
	 * @param op 用户实体
	 * @param id 用户id或登录名
	 * @throws EntityNotFoundException
	 */
	private void userIsNotExist(Optional<User> op, String id) throws EntityNotFoundException {
		if (!op.isPresent()) {
			String msg = String.format("登录名为%s的用户不存在！", id);
			logger.warn(msg);
			throw new EntityNotFoundException(msg);
		}
	}
	/**
	 * 校验密码是否一致
	 * @param user
	 * @param pwd
	 * @throws BadCredentialsException
	 */
	private void checkPassword(User user, String pwd) throws BadCredentialsException {
		boolean isValid = user.getPassword().equalsIgnoreCase(generatePassword(user.getUsername(), pwd));
		if (!isValid) {
			String msg = String.format("登录名为%s的用户密码错误！", user.getUsername());
			logger.warn(msg);
			throw new BadCredentialsException(msg);
		}
	}
	
	/**
	 * 检验用户是否锁定
	 * @param user
	 * @throws LockedException
	 */
	private void checkLocked(User user) throws LockedException {
		if(!user.getValid()) {
			String msg = String.format("登录名为%s的用户已被锁定！", user.getUsername());
			logger.warn(msg);
			throw new LockedException(msg);
		}
	}
		
	/**
	 * 生成密码  password = MD5(MD5(id+密码))
	 * @param username
	 * @param password
	 * @return
	 */
	private String generatePassword(String username, String password) {
		return SecureUtil.md5(SecureUtil.md5(username + password));
	}
	
	/**
	 * 检验实体id是否合法
	 * @param id
	 * @throws Exception
	 */
	private void checkId(Long id) throws Exception {
		if (id <= 0) {
			String msg = "用户的id小于等于0";
			logger.warn(msg);
			throw new Exception(msg);
		}
	}
}
